package
{
	import com.flashandmath.dg.display.*;
	import com.flashandmath.dg.objects.*;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.filters.BlurFilter;
	import flash.geom.Point;
	import flash.utils.Timer;
	import flash.utils.getTimer;

	public class Effect extends Bitmap
	{
		private var origin:Point;
		private var waitCount:int;
		private var count:int;
		private var dropsToAddEachFrame:int;
		private var display:DiskParticleDisplay;
		private var blur:BlurFilter;
		
		private var baseColorR:Number;
		private var baseColorG:Number;
		private var baseColorB:Number;
		private var randomColorR:Number;
		private var randomColorG:Number;
		private var randomColorB:Number;
		private var maxColorComponentDistance:Number;
		private var phaseR:Number;
		private var phaseG:Number;
		private var phaseB:Number;
		private var targetPhaseR:Number;
		private var targetPhaseG:Number;
		private var targetPhaseB:Number;
		private var lastTargetPhaseR:Number;
		private var lastTargetPhaseG:Number;
		private var lastTargetPhaseB:Number;
		private var phaseShiftDuration:Number;
		private var phaseShiftCount:Number;
		private var minColorComponentValue:Number;
		private var particleColor:uint;
		
		private var theta:Number;
		private var phi:Number;
		private var mag:Number;
		
		private var mouseGravity:Number;
		private var attractionOn:Boolean;
		
		public var timer:Timer;
		
		public function Effect(w:int,h:int) {
			
			origin = new Point(0,0);
			waitCount = 1;
			count = waitCount-1;
			dropsToAddEachFrame = 1;  	//Set this to 2 or 3 for a more dense display,
			//but be aware that CPU usage will increase.
			
			targetPhaseR = 4;
			targetPhaseG = 3;
			targetPhaseB = 0;
			minColorComponentValue = 32;
			phaseShiftDuration = 2000;
			phaseShiftCount = phaseShiftDuration - 1;
			
			mouseGravity = 1;
			
			blur = new BlurFilter(5,5);
			
			display = new DiskParticleDisplay(w,h, true);
			
			//We will be setting colors of particles explicitly in the code here
			//rather than using the color randomization options in the DiskParticle class:
			display.randomizeColor = false;
			
			display.gravity = 0;
			
			bitmapData = new BitmapData(display.displayWidth, display.displayHeight, false, 0);
			attractionOn = false;
			
			timer = new Timer(10,0);
			timer.start();
			
			timer.addEventListener(TimerEvent.TIMER, onEnter);
		}
		
		
		private function onEnter(evt:Event):void {	
			//The red, green and blur color components are changed according to sinusoidal
			//functions.  However, to add some randomness while maintaining smoothness, these
			//sinusoidal functions have phase shifts which gradually change to randomly
			//chosen target values.
			phaseShiftCount++;
			if (phaseShiftCount >= phaseShiftDuration) {		
				phaseShiftCount = 0;
				lastTargetPhaseR = targetPhaseR;
				lastTargetPhaseG = targetPhaseG;
				lastTargetPhaseB = targetPhaseB;
				targetPhaseR = Math.random()*6.283;
				targetPhaseG = Math.random()*6.283;
				targetPhaseB = Math.random()*6.283;		
			}
			
			phaseR = lastTargetPhaseR + phaseShiftCount/phaseShiftDuration*(targetPhaseR - lastTargetPhaseR);
			phaseG = lastTargetPhaseG + phaseShiftCount/phaseShiftDuration*(targetPhaseG - lastTargetPhaseG);
			phaseB = lastTargetPhaseB + phaseShiftCount/phaseShiftDuration*(targetPhaseB - lastTargetPhaseB);
			
			baseColorR = 32 + (0.5+0.5*Math.cos(phaseR+getTimer()*0.00017))*223;
			baseColorG = 32 + (0.5+0.5*Math.cos(phaseG-getTimer()*0.00027))*223;
			baseColorB = 32 + (0.5+0.5*Math.cos(phaseB+getTimer()*0.00035))*223;
			
			//add a particle
			count++
			if (count >= waitCount) {
				count =0;		
				for (var i:int = 0; i <= dropsToAddEachFrame-1; i++) {
					
					//The color is chosen randomly, but with components
					//greater than the base color (to avoid colors that are too dark).
					//Using two random numbers multiplied together favors colors 
					//closer to the base color.
					randomColorR = baseColorR+Math.random()*Math.random()*(255-baseColorR);
					randomColorG = baseColorG+Math.random()*Math.random()*(255-baseColorG);
					randomColorB = baseColorB+Math.random()*Math.random()*(255-baseColorB);
					
					particleColor = int(randomColorR) << 16 | int(randomColorG) << 8 | int(randomColorB);
					
					//we set an initial velocity in a random 3D direction (projected to two 
					//dimensions) using spherical coordinates
					theta = Math.random()*Math.PI*2;
					phi = Math.random()*Math.PI;
					mag = 0.4+0.4*(Math.random());
					var thisDrop = display.addDrop(
						display.displayWidth/2, 
						display.displayHeight/2, 
						mag*Math.sin(phi)*Math.cos(theta), 
						mag*Math.sin(phi)*Math.sin(theta),
						particleColor);
					//Try setting the airResistanceFactor below to something else (like 0.02) to 
					//achieve a more "viscous" effect.  Increase the magnitude of 
					//the velocity above ("mag") if you do this.
					thisDrop.airResistanceFactor = 0;  
					//thisDrop.airResistanceFactor = 0;
					//thisDrop.dotAlphaVariance = 1;
					//thisDrop.breakawayTime = 100;
					thisDrop.alpha = 1;
					thisDrop.setEnvelope(40,200,40,
						4,10,10,
						0,0.4+0.8*Math.random(),0,0);
					//parameters for setEnvelope() are:
					//				attack, hold, decay, 
					//				attack variance, hold variance, decay variance,
					//				rInit, rHold, rLast, rVariance
					thisDrop.redraw();
				}
				
				
				//We update the acceleration of the particles according to mouse distance
				if (attractionOn) {
					var drop:DiskParticle = display.onStageList.first;
					var distSquare:Number;
					while (drop != null) {
						
						distSquare = Math.max(1,(drop.pos.x - mouseX)*(drop.pos.x - mouseX)+(drop.pos.y - mouseY)*(drop.pos.y - mouseY));
						drop.accel.x = -mouseGravity*(drop.pos.x - mouseX)/distSquare;
						drop.accel.y = -mouseGravity*(drop.pos.y - mouseY)/distSquare;
						
						drop = drop.next;
					}
				}
				
			}
			
			//update drops
			display.update();
			
			bitmapData.applyFilter(bitmapData,bitmapData.rect,origin,blur);	
			bitmapData.draw(display);
		}
		
	}
}